using System;
using CI.Misc;
using NUnit.Framework;
using CI;
using CI.Interfaces;
using CI.Organism;
using Rhino.Mocks;

namespace Mesopotamia.UnitTests.Organism
{
    [TestFixture]
    public class DNATests
    {
        private IDNA _dna;
        private IOrganism _organism;
        private IChromosomeCollection _chromosomes;
        private IChromosome _chromosome;
        private IGeneCollection _genes;
        private IGene _gene;
        private CI.Organism.HBOffsetTime _hbOffsetTime;
        private CI.Organism.HBOffsetTimeCell _hbOffsetTimeCell;
        MockRepository _mocks;
        private IRequirementCollection _requirements;
        private CI.Organism.HBOffsetTime _requirement;
        private ICellCollection _cells = new CI.Organism.CellCollection();
        private ICell _cell;
        private readonly IHostingEnvironment _hostingEnvironment = new CI.Mesopotamia.MSRBHost(new MockHostingEnvironmentPhysical(), new CI.Mesopotamia.ScenarioLocalXML());
        private readonly SimEnv _simEnv = SimEnv.Instance;

        /// <summary>Test Harness setup</summary>
        [SetUp]
        public void Setup()
        {
            // reset
            _dna = new CI.Organism.DNA();
            _hostingEnvironment.Organisms = new CI.Organism.OrganismCollection();
            _organism = new CI.Organism.Organism(_hostingEnvironment);
            _organism.Cells = new CI.Organism.CellCollection();
            _chromosome = new CI.Organism.Chromosome(Guid.NewGuid());
            _chromosomes = new CI.Organism.ChromosomeCollection();
            _gene = new CI.Organism.GeneCellular(_organism, Guid.NewGuid());
            _genes = new CI.Organism.GeneCollection();
            _mocks = new MockRepository();
            _requirements = new RequirementCollection();
            _cell = (ICell)(new CI.Organism.Amoeba(_organism, Guid.NewGuid()));
            _hbOffsetTime = new HBOffsetTime(_organism, 1, ComparisonType.Equal, Guid.NewGuid());
            _hbOffsetTimeCell = new HBOffsetTimeCell(_organism, 1, _cell, ComparisonType.Equal, Guid.NewGuid());

            // create dna structure
            _organism.DNA = _dna;
            // setup the chromosome collection
            _dna.Chromosomes = _chromosomes;
            // add a chromosome
            _chromosomes.Add(_chromosome);
            // setup the gene
            // add a gene collection
            _chromosome.Genes = _genes;
            // add a gene
            _genes.Add(_gene);
            // add a requirement colleciton to that gene
            _gene.Requirements = _requirements;
        }

        /// <summary>Lets Make sure the grow method has Chromosones to process</summary>
        [Test, ExpectedException(typeof(CI.Organism.DNAException), ExpectedMessage = "Chromosome Collection is Empty(null)")]
        public void GrowNullChromosomesDNAException()
        {
            // clear the chromosones
            _dna.Chromosomes = null;

            // grow the childOrganism from the dna
            _dna.Grow();

        }

        /// <summary>Lets Make sure the grow method has Genes in the Chromosones to process</summary>
        [Test, ExpectedException(typeof(CI.Organism.DNAException), ExpectedMessage = "Gene Collection is Empty(null)")]
        public void GrowNullGenesDNAException()
        {
            // clear the gene in the first chromosome
            _dna.Chromosomes[0].Genes = null;

            // grow the childOrganism from the dna
            _dna.Grow();
        }

        /// <summary>During Grow if the Gene has not been actioned test it</summary>
        [Test]
        public void GrowGeneActionableTrue()
        {

            // clear the genes in the colleciton set
            _genes.Clear();

            // mock the gene class
            _gene = _mocks.DynamicMock<GeneCellular>(_organism, Guid.NewGuid());

            // add a  single gene
            _genes.Add(_gene);

            // set the only gene in the collection
            _gene.Actioned = false;

            // make sure actionable is not called
            using (_mocks.Record())
            {
                Expect.Call(_gene.Actionable()).Return(true);
            }

            // run through the grow sequence
            using (_mocks.Playback())
            {
                _dna.Grow();
            }

        }

        /// <summary>Lets Make sure the actionable method in Genes has some requiements to work off</summary>
        [Test, ExpectedException(typeof(CI.Organism.DNAException), ExpectedMessage = "Requirement Collection is Empty(null)")]
        public void GrowGeneActionableNullRequirementListDNAException()
        {
            // clear the requirement list
            _gene.Requirements = null;

            // test the actionable method
            _gene.Actionable();
        }

        /// <summary>Lets Make sure the actionable method in Genes has some requiements to work off (Count=0)</summary>
        [Test, ExpectedException(typeof(CI.Organism.DNAException), ExpectedMessage = "Requirement Collection is Empty(null)")]
        public void GrowGeneActionableZeroCountRequirementListDNAException()
        {
            // clear the requirement list
            _gene.Requirements.Clear();

            // test the actionable method
            _gene.Actionable();
        }

        /// <summary>During Grow if the Gene requirements fail, actionable should fail</summary>
        [Test]
        public void GrowGeneActionableRequirementStateFalseFalse()
        {
            // stub the one and only requirement
            _requirement = _mocks.Stub<HBOffsetTime>(_organism, (UInt32)1, ComparisonType.Equal, Guid.NewGuid());

            // clear and set a single requirement the one we just mocked
            _gene.Requirements.Clear();
            _gene.Requirements.Add(_requirement);

            // set it up for false
            SetupResult.For(_requirement.State()).Return(false);

            // call and make sure we actionable false
            Assert.IsFalse(_gene.Actionable());
        }

        /// <summary>argument checker</summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Organism")]
        public void DNAMutateNullOrganism()
        {
            _dna.Mutate(0, null);
        }

        /// <summary>argument checker</summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Organism")]
        public void ChromosomeMutateNullOrganism()
        {
            _chromosome.Mutate(0, null);
        }

        /// <summary>argument checker</summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Organism")]
        public void ChromosomesMutateNullOrganism()
        {
            _chromosomes.Mutate(0, null);
        }

        /// <summary>argument checker</summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Organism")]
        public void GeneMutateNullOrganism()
        {
            _gene.Mutate(0, null);
        }

        /// <summary>argument checker</summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Organism")]
        public void GenesMutateNullOrganism()
        {
            _genes.Mutate(0, null);
        }

        /// <summary>argument checker</summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Organism")]
        public void GeneCtorNullOrganism()
        {
            CI.Organism.Gene _gene = new CI.Organism.GeneCellular(null, Guid.NewGuid());
        }

        /// <summary>test null organism being passed to it</summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Organism")]
        public void GeneCreateNewGeneException()
        {
            Gene.CreateNewGene(0, null);
        }

        /// <summary>test to see if it created a new gene</summary>
        [Test]
        public void GeneCreateNewGeneTrue()
        {
            Assert.IsNotNull(Gene.CreateNewGene(0, _organism), "New gene not created");
        }
    }
}

